package com.sandyz.virtualcam

import android.annotation.SuppressLint
import android.app.Application
import android.app.Instrumentation
import android.content.res.XModuleResources
import android.content.res.XResources
import com.sandyz.virtualcam.hooks.IHook
import com.sandyz.virtualcam.hooks.VirtualCameraBiliSmile
import com.sandyz.virtualcam.hooks.VirtualCameraDy
import com.sandyz.virtualcam.hooks.VirtualCameraPdd
import com.sandyz.virtualcam.hooks.VirtualCameraWs
import com.sandyz.virtualcam.utils.HookUtils
import com.sandyz.virtualcam.utils.xLog
import de.robv.android.xposed.IXposedHookInitPackageResources
import de.robv.android.xposed.IXposedHookLoadPackage
import de.robv.android.xposed.IXposedHookZygoteInit
import de.robv.android.xposed.IXposedHookZygoteInit.StartupParam
import de.robv.android.xposed.XC_MethodHook
import de.robv.android.xposed.XposedHelpers
import de.robv.android.xposed.callbacks.XC_InitPackageResources
import de.robv.android.xposed.callbacks.XC_LoadPackage

/**
 * XVirtual Camera 主入口类
 * 实现了Xposed框架的三个主要接口：
 * 1. IXposedHookLoadPackage: 处理应用加载
 * 2. IXposedHookZygoteInit: 处理Zygote初始化
 * 3. IXposedHookInitPackageResources: 处理资源注入
 * 
 * @author sandyz987
 * @date 2023/11/17
 */
class HookMain : IXposedHookLoadPackage, IXposedHookZygoteInit, IXposedHookInitPackageResources {

    companion object {
        // 1. 模块路径相关变量
        public var modulePath: String? = null  // 模块文件路径
        private var moduleRes: String? = null  // 模块资源路径
        var xResources: XResources? = null     // Xposed资源对象

        /**
         * 2. 加载原生库
         * 按顺序加载所有架构的原生库文件
         * 支持的架构：arm64-v8a, armeabi-v7a, arm64, x86, x86_64
         */
        @SuppressLint("UnsafeDynamicallyLoadedCode")
        fun loadNative() {
            // 2.1 定义所有需要加载的原生库
            val libs = arrayOf(
                // arm64-v8a架构库
                "$modulePath/lib/arm64-v8a/libijkffmpeg.so",  // FFmpeg库
                "$modulePath/lib/arm64-v8a/libijksdl.so",     // SDL库
                "$modulePath/lib/arm64-v8a/libijkplayer.so",  // ijkplayer播放器库
                "$modulePath/lib/arm64-v8a/libencoder.so",    // 编码器库

                // armeabi-v7a架构库
                "$modulePath/lib/armeabi-v7a/libijkffmpeg.so",
                "$modulePath/lib/armeabi-v7a/libijksdl.so",
                "$modulePath/lib/armeabi-v7a/libijkplayer.so",
                "$modulePath/lib/armeabi-v7a/libencoder.so",

                // arm64架构库
                "$modulePath/lib/arm64/libijkffmpeg.so",
                "$modulePath/lib/arm64/libijksdl.so",
                "$modulePath/lib/arm64/libijkplayer.so",
                "$modulePath/lib/arm64/libencoder.so",

                // x86架构库
                "$modulePath/lib/x86/libijkffmpeg.so",
                "$modulePath/lib/x86/libijksdl.so",
                "$modulePath/lib/x86/libijkplayer.so",
                "$modulePath/lib/x86/libencoder.so",

                // x86_64架构库
                "$modulePath/lib/x86_64/libijkffmpeg.so",
                "$modulePath/lib/x86_64/libijksdl.so",
                "$modulePath/lib/x86_64/libijkplayer.so",
                "$modulePath/lib/x86_64/libencoder.so",
            )
            // 2.2 遍历加载所有库文件
            libs.forEach {
                try {
                    System.load(it)
                    xLog("loadNative success $it")
                } catch (_: Throwable) {
                    // 忽略加载失败的情况
                }
            }
        }
    }

    // 3. 定义所有Hook实现类
    private val hooks = listOf(
        VirtualCameraBiliSmile(),  // 哔哩哔哩直播Hook
        VirtualCameraDy(),         // 抖音Hook
        VirtualCameraPdd(),        // 拼多多Hook
        VirtualCameraWs(),         // 微视Hook
    )

    /**
     * 4. Zygote初始化
     * 在Zygote进程启动时调用，初始化模块路径
     */
    override fun initZygote(startupParam: StartupParam) {
        // 4.1 设置模块路径
        modulePath = startupParam.modulePath.substring(0, startupParam.modulePath.lastIndexOf('/'))
        moduleRes = startupParam.modulePath
    }

    /**
     * 5. 处理资源初始化
     * 在应用资源初始化时调用，注入自定义资源
     */
    override fun handleInitPackageResources(resparam: XC_InitPackageResources.InitPackageResourcesParam?) {
        // 5.1 保存资源对象
        xResources = resparam?.res
        // 5.2 检查是否支持当前应用
        var supported = (resparam?.packageName == "com.sandyz.virtualcam")
        hooks.forEach {
            it.getSupportedPackages().forEach { pkg ->
                if (pkg == resparam?.packageName) {
                    supported = true
                }
            }
        }
        // 5.3 如果支持，则注入资源
        if (supported) {
            val modRes = XModuleResources.createInstance(moduleRes, resparam?.res)
            hooks.forEach {
                it.registerRes(modRes)
            }
        }
    }

    /**
     * 6. 处理应用加载
     * 在应用启动时调用，初始化Hook
     */
    override fun handleLoadPackage(lpparam: XC_LoadPackage.LoadPackageParam) {
        // 6.1 初始化Hook工具类
        HookUtils.init(lpparam)

        // 6.2 遍历所有Hook实现
        hooks.forEach {
            // 6.3 检查是否支持当前应用
            var supported = (lpparam.packageName == "com.sandyz.virtualcam")
            it.getSupportedPackages().forEach { pkg ->
                if (pkg == lpparam.packageName) {
                    supported = true
                }
            }
            if (!supported) {
                // 6.4 不支持的应用，记录日志
                xLog("init>>>>${it.getName()}>>>> unsupported! ===================== package: ${lpparam?.packageName} process: ${lpparam?.processName}")
            } else {
                // 6.5 支持的应用，进行初始化
                xLog("init>>>>${it.getName()}>>>> package: ${lpparam.packageName} process: ${lpparam.processName}")
                // 6.6 加载原生库
                loadNative()
                // 6.7 Hook应用创建方法
                XposedHelpers.findAndHookMethod(Instrumentation::class.java, "callApplicationOnCreate", Application::class.java, object : XC_MethodHook() {
                    override fun afterHookedMethod(param: MethodHookParam) {
                        // 6.8 在应用创建后初始化Hook
                        init(it, lpparam)
                    }
                })
            }
        }
    }

    /**
     * 7. 初始化Hook
     * 初始化Hook环境并开始Hook操作
     */
    fun init(hook: IHook, lpparam: XC_LoadPackage.LoadPackageParam?) {
        // 7.1 初始化Hook环境
        hook.init(lpparam?.classLoader)
        // 7.2 开始Hook操作
        hook.hook(lpparam)
        xLog("Hook初始化完成: ${hook.getName()}")
    }
}